﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using System.ComponentModel;
using Microsoft.Xna.Framework.Input;
using BEPUphysics;

namespace The_LarX
{
    public delegate void ChaseCameraHelperMethod();
    public delegate Matrix ChaseCameraCustomRotationMatrix();
    public class ChaseCamera : Camera3D
    {
#if WINDOWS
        [Category("Transformação")]
        [Description("A velocidade de movimentação da Câmera")]
#endif
        public float MovementSpeed
        {
            get { return speed; }
            set { speed = value; }
        }
        protected float speed = 30;

#if WINDOWS
        [Category("Renderização")]
        [Description("A distância que deve ser mostrada da Câmera")]
#endif
      

        public override Vector3 Position { get; set; }

        private Vector3 pos;

        private I3DObject FollowActor;

        public Vector3 TargetOffset { get; set; }

        public Vector3 Forward { get { return -FollowActor.RotationMatrix.Forward; } }        

        public ChaseCamera(I3DObject actor, GameScreen Screen)
            : base(Screen)
        {            
            FarPlane = 50;
            Projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, Engine.AspectRatio, 1.0f, FarPlane);

            Target = new Vector3(0, 0, 0);

            Actor.ComponentParent = this;

            NearPlane = 1;            

            FollowActor = actor;
        }
        public ChaseCamera()
        {
            FarPlane = 50;
            Projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, AspectRatio, 1.0f, FarPlane);

            Target = new Vector3(0, 0, 0);

            NearPlane = 1;
            FarPlane = 100;

            Actor.ComponentParent = this;
        }

        public override void Update()
        {
            Projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, AspectRatio, NearPlane, FarPlane);

            base.Update();
        }

        public override void Draw()
        {
            base.Draw();

            if (Engine.PlayMode)
            {
            }
            else
            {
                Position = Actor.Position;
            }

            UpdateViewMatrix();
        }

        public ChaseCameraHelperMethod WhenSetMatrix;

        public ChaseCameraCustomRotationMatrix GetCustomRotationMatrix;

        private void UpdateViewMatrix()
        {
            if (FollowActor is Actor)
            {
                Actor actor = FollowActor as Actor;
                actor.Draw();
                if (WhenSetMatrix != null)
                    WhenSetMatrix();
            }

            Vector3 campos = Actor.Position;
            Matrix RotationMatrix;
            if (GetCustomRotationMatrix == null)
                RotationMatrix = FollowActor.RotationMatrix;
            else
                RotationMatrix = GetCustomRotationMatrix();
            campos = Vector3.Transform(campos, RotationMatrix);
            campos += FollowActor.Position;
            Position = campos;

            Vector3 camup = new Vector3(0, 1, 0);
            camup = Vector3.Transform(camup, RotationMatrix);

            Vector3 finalTargetOffset = Vector3.Transform(TargetOffset, RotationMatrix);
            View = Matrix.CreateLookAt(campos, FollowActor.Position + finalTargetOffset, camup);
        }

        public override void SetToInitialState()
        {
            base.SetToInitialState();

            Actor.SetToInitialState();
        }

        public override void SerializeData()
        {
            base.SerializeData();

            Data.AddData("ChaseCamera.Position", this.Position);
            Data.AddData("ChaseCamera.Target", this.Target);
            Data.AddData("ChaseCamera.TargetOffset", this.TargetOffset);
            Data.AddData("ChaseCamera.ActorName", FollowActor.Name);
            Data.AddData("ChaseCamera.NearPlane", this.NearPlane);
            Data.AddData("ChaseCamera.FarPlane", this.FarPlane);
        }
        public override void DeserializeData()
        {
            base.DeserializeData();

            this.Position = Data.GetData<Vector3>("ChaseCamera.Position");
            this.Target = Data.GetData<Vector3>("ChaseCamera.Target");
            this.TargetOffset = Data.GetData<Vector3>("ChaseCamera.TargetOffset");
            string actorName = Data.GetData<string>("ChaseCamera.ActorName");
            for (int i = 0; i < EngineSystem.Actors.Count; i++)
            {
                if (EngineSystem.Actors[i].Name == actorName)
                {
                    FollowActor = EngineSystem.Actors[i];
                }
            }

            this.NearPlane = Data.GetData<float>("ChaseCamera.NearPlane");
            this.FarPlane = Data.GetData<float>("ChaseCamera.FarPlane");

            Projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, Engine.AspectRatio, 1.0f, FarPlane);

            if (Data.IsService)
            {
                Engine.Services.AddService(typeof(Camera3D), this);
            }
        }
    }
}